/**
 * Software License, Version 1.0
 * 
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 * 
 *
 *Redistribution and use in source and binary forms, with or without 
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the 
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For 
 * further information contact the Community Grids Lab at 
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and 
 * wherever such third-party acknowledgments normally appear.
 * 
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering, 
 * shall not be used to endorse or promote products derived from this software 
 * without prior written permission from Indiana University.  For written 
 * permission, please contact the Advanced Research and Technology Institute 
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering, 
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 * 
 *
 * Indiana University provides no reassurances that the source code provided 
 * does not infringe the patent or any other intellectual property rights of 
 * any other entity.  Indiana University disclaims any liability to any 
 * recipient for claims brought by any other entity based on infringement of 
 * intellectual property rights or otherwise.  
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO 
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF 
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS. 
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS", 
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.  
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR 
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION 
 *GENERATED USING SOFTWARE.
 */
package cgl.narada.discovery.topics.messages;

import java.io.IOException;
import java.io.Serializable;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;

import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.log4j.Logger;

import cgl.narada.service.ServiceException;
import cgl.narada.service.security.impl.EntityOperationsImpl;
import cgl.narada.service.security.securityprovider.EncryptDecryptUtil;
import cgl.narada.util.ObjectMarshaller;

import cgl.narada.service.security.securityprovider.CertificateManager;
import cgl.narada.service.security.securityprovider.CertificateUtil;

/**
 * Encapsulates the encrupted key and encrupted Payload <br>
 * Created on Apr 18, 2005
 * 
 * @author Harshawardhan Gadgil (hgadgil@grids.ucs.indiana.edu)
 */

public class EncryptedMessagePayload implements Serializable {

   static Logger log = Logger.getLogger("EncryptedMessagePayload");
   private byte[] encryptedKey;
   //   private byte[] encryptedDigest;
   private byte[] encryptedPayload;

   private EncryptedMessagePayload() {
   }

   public byte[] getBytes() {
      try {
         return ObjectMarshaller.marshall(this);
      } catch (IOException e) {
         log.error("", e);
         return null;
      }
   }

   public static EncryptedMessagePayload createObjectFromBytes(
            byte[] objectBytes) {
      try {
         return (EncryptedMessagePayload) ObjectMarshaller
                  .unmarshall(objectBytes);
      } catch (IOException e) {
         log.error("", e);
      } catch (ClassNotFoundException e) {
         log.error("", e);
      }
      return null;
   }

   /**
    * Creates a new secret key, encrypts the payload with the new SecretKey. Then
    * using the public key, the secret key is encoded and a new instance of
    * EncryptedMessagePAyload is returned
    * 
    * @param payload
    * @return
    */
   public static EncryptedMessagePayload generate(byte[] payload,
            PublicKey pubkey) {
      EncryptedMessagePayload emp = new EncryptedMessagePayload();

      System.out.println("Encrypting Payload of size: " + payload.length + "bytes");

      SecretKey key = emp.getNEWSecretKey();
      emp.encryptedPayload = EncryptDecryptUtil.encrypt(key, payload);

      try {
	  byte[] secretKeyBytes = key.getEncoded();
	 System.out.println("encrypting SecretKey of size: " + secretKeyBytes.length + "bytes");
         EntityOperationsImpl entityOps = new EntityOperationsImpl();         
         emp.encryptedKey = entityOps.encryptPayload(pubkey, secretKeyBytes);
      } catch (Exception e) {
         log.error("", e);
         return null;
      }

      return emp;
   }

   /**
    * Returns the decrypted payload. Decryption is done using the private key
    * 
    * @param privatekey -
    *           private key for decrypting the secret key
    * @return array of payload bytes if successful, NULL otherwise
    */
   public byte[] getDecryptedPayload(PrivateKey privatekey) {

      // First init the cipher decryption routine...

      EntityOperationsImpl entityOps = null;
      try {
         entityOps = new EntityOperationsImpl();
      } catch (ServiceException e1) {
         log.error("Unable to start EntityOperationsImpl "
                  + "Encryption/Decryption:", e1);
         return null;
      }

      // First decrypt the secret key
      SecretKeySpec key = null;
      try {
         byte[] secretKeyBytes = entityOps.decryptPayload(privatekey,
                  this.encryptedKey);

         key = new SecretKeySpec(secretKeyBytes, "DES");
      } catch (Exception e) {
         log.error("Unable to decrypt Secret Key: ", e);
         return null;
      }

      // Verify the digest

      // Now decrypt the payload using the secret key
      byte[] payloadBytes = EncryptDecryptUtil.decrypt(key,
               this.encryptedPayload);

      return payloadBytes;
   }

   /**
    * Generates a new SecretKey to use.
    * 
    * @return a DES secret key if successful, NULL otherwise
    */
   private SecretKey getNEWSecretKey() {
      try {
         KeyGenerator kg = KeyGenerator.getInstance("DES");
         kg.init(56, new SecureRandom());
         return kg.generateKey();
      } catch (NoSuchAlgorithmException e) {
         // TODO Auto-generated catch block
         // e.printStackTrace();
         log.error("", e);
      }
      return null;
   }

    public static void main(String[] args) {
	byte[] data = new byte[1024]; // some data

	CertificateManager certMan = new CertificateManager();
	
	// To use default password use null.
	// OR specify a different password in the second parameter
	certMan.init("/home/hgadgil/mgmt-jdk1.6/nb-2.0.2/keystore/NBSecurityKeys.test",
		     null);
	
	PublicKey pubkey = CertificateUtil.getPublicKey(certMan, "kmc1");
	
	EncryptedMessagePayload emp = EncryptedMessagePayload.generate(data, pubkey);
	System.out.println("DONE !");
    }

}
